/**
 * AOP style event handling
 **/
(function() {
	var _eventElements = [];
    var _eventListeners = [];
    var currentEventOperator;
    var isIE = !(!document.all);
	events = { 
		/* Add a listener for the execution of the given function slot on the given object.
		 * When object[functionName]() is executed the handler is called.
		 * The optional listeningType parameter specificies (using the constants below) whether handler
		 * should be fired before, after or around the previously registered handler or default action
		 * If a the event is a DOM event, than you can provide the name of the event instead of the
		 * handler name, that is you can register for the click events with "click" (event name) or "onclick" (handler name).
		 */
		addListener : function(object,functionName,handler,listeningType) {
			if (!handler)
				throw new Error("No handler provided");
			var isDOM = object.nodeType;
			if (isDOM && functionName.substring(0,2) != "on") functionName = "on" + functionName;
			var handlers;
			var oldHandler = object[functionName];
			if (oldHandler && oldHandler.$_handlers)
				handlers = oldHandler.$_handlers;
			else
			{
				if (isDOM && isIE) { // this is for cleanup
					_eventElements.push(object);
					_eventListeners.push(functionName);
				}
				object[functionName] = function(evt) {
					if (isDOM && !evt) { // this is for IE
						arguments[0] = evt = window.event || parent.event;
						evt.target = evt.srcElement;
						arguments.length = 1;
						evt.preventDefault = events.iePreventDefault;
						evt.stopPropagation = events.ieStopPropagation;
					}
					if (!isIE)
						event = evt; // make it globally availabe for IE style access
					currentEventOperator=function(action) {
						if (action==0)
							handlers.splice(i,1);
						if (action==1)
							return [oldHandler,object];
					}
					for (var i =  handlers.length; i>0;)
					{
						i--;
//						try { // you can optionally try catch it so all errors from events are displayed with an alert
						var retValue = handlers[i].apply(object,arguments);
//						} catch (e) {alert(e) };
					}						
					return retValue; 
				}
				handlers = object[functionName].$_handlers = oldHandler?[oldHandler]:[];
			}
			for (var i = 0; i < handlers.length; i++)
				if (handlers[i] == handler)
					return handler; // already registered
			if (listeningType == 1)
				handlers.push(handler);
			if (!listeningType) // or == 0
				handlers.splice(0,0,handler); // insert it at the beginning
		},
		/** Remove a previously a previously registered handler from listening */
		removeListener : function(object,functionName,handler) {
			var isDOM = object.nodeType;
			if (isDOM && functionName.substring(0,2) != "on") functionName = "on" + functionName;
			var handlers = object[functionName].$_handlers;
			var index = handlers.indexOf(handler);
			if (index >= 0)
				handlers.splice(index,1);				
		},
		/* Simulate the W3C action for IE*/
        iePreventDefault: function() { 
            this.returnValue = false;
        },
        /* Simulate the W3C action for IE*/
        ieStopPropagation: function() { 
            this.cancelBubble = true;
        },
        // The different styles of listening
		AFTER:0,  // indicates listener fires after the previously registered or default action
		BEFORE:1,// indicates listener fires before the previously registered or default action
		AROUND:2,// indicates listener fires and must call doNext for the previously registered or default action
		/* This can be called when in a handler to remove the handler as a listener for the current event */
		stopListening : function() {
			currentEventOperator(0);
		},
		/* In around handling, call this for the previous registered event */
		doNext : function() {
			var callSet = currentEventOperator(1);
			return callSet[0].apply(callSet[1],arguments);
		},
		/** remove all the listeners for IE, so there is no memory leaks */
		cleanupListeners : function() { 
			if (isIE) {
				for (var i = 0; i < _eventElements.length; i++) {
					_eventElements[i][_eventListeners[i]] = null;
				}
				_eventElements=null;
			}
		}
	}
})();